﻿#region

using Microsoft.AspNetCore.Components.Server.Circuits;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Vin.Extension.Framework.Dto;
using Vin.Extension.Framework.Models;
using Vin.Tool.AspNetCore.Extension;
using Vin.Tool.AspNetCore.Singleton;
using Vin.Tool.Core.ExceptionCategory;
using Vin.Tool.Core.JsonCategory;
using Vin.Tool.Core.NetCategory;
using Vin.Tool.Core.StreamCategory;
using Vin.Tool.Domain.SystemModel;

#endregion

namespace Vin.Extension.Framework.Aop;

[AttributeUsage(AttributeTargets.Method)]
public class VinLogAttribute : Attribute, IAsyncActionFilter
{
    public async Task<VinHttpContextInfoModel> GetHttpContextInfo(ActionExecutingContext requestContext,
        ActionExecutedContext responseContext)
    {
        var contextInfo = requestContext.HttpContext.GetClientDetail();
        var model = new VinHttpContextInfoModel()
        {
            ControllerPath = requestContext.Controller.ToString(),
            ActionPath = requestContext.ActionDescriptor.DisplayName,
            Url = requestContext.HttpContext.Request.Path,
            Method = requestContext.HttpContext.Request.Method,
            Header = requestContext.HttpContext.Request.Headers,
            Params = requestContext.HttpContext.Request.Query,
            Data = !requestContext.HttpContext.Request.HasFormContentType
                ? await requestContext.HttpContext.ReadToJson()
                : requestContext.HttpContext.FormDictionary(),
            Curl = requestContext.HttpContext.ToCurl(),
            // Code = ""
            // Body = ""
            // Exception = ""
            Ip = contextInfo.Ip,
            Location = contextInfo.Location,
            Browser = contextInfo.Browser,
            Os = contextInfo.Os,
            UserAgent = contextInfo.UserAgent,
            Code = requestContext.HttpContext.Response.StatusCode,
            Body = responseContext.Result.ToJson()
        };

        if (responseContext.Result is JsonResult jsonResult)
        {
            model.Code = jsonResult.StatusCode;
            model.Body = jsonResult.Value;
        }

        if (responseContext.Result is ObjectResult objectResult)
        {
            model.Code = objectResult.Value is ApiResult apiResult ? apiResult.Code : objectResult.StatusCode;
            model.Body = objectResult.Value;
        }

        if (responseContext.Exception != null)
        {
            model.Exception = responseContext.Exception.ExceptionMessage();
            //responseContext.Exception.Message + " " + responseContext.Exception.StackTrace;
        }

        return model;
    }

    public async Task<(VinHttpContextInfoModel, int)> GetResult(ActionExecutingContext context,
        ActionExecutionDelegate next)
    {
        var startTime = DateTime.Now;
        var responseContext = await next();
        var endTime = DateTime.Now;
        var httpContextInfo = await GetHttpContextInfo(context, responseContext);
        var costTime = (endTime - startTime).Milliseconds;

        return (httpContextInfo, costTime);
    }

    public virtual async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
    {
        await next();
    }
}